home *** CD-ROM | disk | FTP | other *** search
- _TEXT SEGMENT WORD PUBLIC 'CODE'
- _TEXT ENDS
-
- _DATA SEGMENT WORD PUBLIC 'DATA'
-
- _DATA ENDS
-
- CONST SEGMENT WORD PUBLIC 'CONST'
- CONST ENDS
-
- _BSS SEGMENT WORD PUBLIC 'BSS'
- ;GLOBAL UNINITIATED DATA GOES HERE
- _BSS ENDS
-
- DGROUP GROUP CONST,_BSS,_DATA
- ;
- ASSUME DS:DGROUP,SS:DGROUP
-
- ;EXTRN EXTERNAL SUBROUTINE CALLS GO HERE
- ;
- ;
- ; _sbdma FAR Procedure for C Written by John A. Ball December 5, 1996
- ;
- ; Copyright (c) 1996 John A. Ball
- ;
- ; You may copy and modify for your own use only!
- ; Please notify me of any errors or suggested enhancements.
- ;
- ; Plays back sound on the Sound Blaster or Sound Blaster Pro
- ;
- ; int error sbdma(char *buffer, unsigned number_read,unsigned frequency,
- ; unsigned voc_pack);
- ;
- ; error=sbdma(Buffer Pointer,Length,Frequency,voc_pack,Volume,channels);
- ;
- ; Buffer Pointer is a Far pointer to the sound buffer (64k max)
- ; Length is the number of sound samples to play
- ; Frequency is the playback frequency in hertz
- ; voc_pack is the DSP dma mode
- ; Volume is the sound volume for SB Pro cards and above
- ; error=0 ok
- ; error 1=DMA in use
- ; error 2=IRQ/DMA not Found
- ; error 3=DSP not responding
- ; error 4=No DSP version
- ; error 5=DMA channel not correct
- ; error 6=IRQ in environment not correct
- ; error 7=IRQ not valid for Sound Blaster
- ; error 8=Number of samples is zero
- ; error -1=Sound Halted
- ;
- _TEXT SEGMENT
- ASSUME CS:_TEXT
- PUBLIC _sbdma,_sb_info,_sbdelay
-
- _sbdma PROC FAR
-
- PARMA EQU [BP+6] ;Sound Buffer Pointer
- PARMB EQU [BP+10] ;Number of samples to play (Length)
- PARMC EQU [BP+12] ;Frequency to playback samples
- PARMD EQU [BP+14] ;VOC Pack mode determines DSP DMA Mode
- PARME EQU [BP+16] ;Volume for playback
- PARMF EQU [BP+18] ;Number of 8 bit channels
- PUSH BP ;Save stack Frame
- MOV BP,SP
- PUSHF
- PUSH DS ;Save registers
- PUSH ES
- PUSH DI
-
- MOV AX,DGROUP ;Set DS = our data segment
- MOV DS,AX
-
- JMP OVERDATA
- _sb_info LABEL WORD
- DMAFLAG DW 0 ;Flag to indicate DMA for DAC in use
- SB_IRQ DW -1 ;Sound Blaster IRQ (default 5)
- TIME_CONST DW 0 ;DSP Time constant
- SAMPLES DW 0 ;Number of samples to play
- SB_IO_ADDR DW 0 ;Sound Blaster I/O Address
- SB_VER DW 0 ;Sound Blaster DSP Version
- SB_DMA DW 1 ;Sound Blaster DMA Channel
- SB_TYPE DW 1 ;Sound Blaster board type
- ERROR DW 0 ;Sound Blaster Hardware Error
- VOLUME DW 0 ;Sound Blaster Playback Volume
- STEREO DW 0 ;Sound Blaster mono or stereo mode
- PRE_MODE DW -1 ;Previous mono stereo mode
- OUT_FILTER DW 0 ;Status of output filter
- IN_DV DW 0 ;In DESQview Flag
- TEMP DW 0 ;Temporary Storage
- BUFFER LABEL WORD
- BUFFER_ADDR DD 0 ;Pointer to Sound Data
- OLD_INTERRUPT LABEL WORD
- OLD_INTERRUPT_ADDR DD 0 ;Location of previous IRQ 5 System Interrupt
- SAVEPIC DB 0 ;Contents of PIC 1
- SAVEPIC2 DB 0 ;Contents of PIC 2
- DMA_MODE DB 014H ;DSP DMA mode
- DSP_SPEED DB 0 ;Indicates whether highspeed dma is required
- SB_TEST DB 0 ;Indicates whether SB has been tested
- IRQ DW 0 ;IRQ from environment
- TESTBUFFER DB 1 DUP(080H)
- OLD_ISR2 LABEL WORD
- OLD_ISR2_ADDR DD 0
- OLD_ISR3 LABEL WORD
- OLD_ISR3_ADDR DD 0
- OLD_ISR5 LABEL WORD
- OLD_ISR5_ADDR DD 0
- OLD_ISR7 LABEL WORD
- OLD_ISR7_ADDR DD 0
- OLD_ISR10 LABEL WORD
- OLD_ISR10_ADDR DD 0
- DSP_DMA_MODE DB 014H, 075H, 077H, 017H, 0C0H, 0C0H, 0B0H, 0B0H
- DMA_PAGE DB 087H, 083H, 081H, 082H
-
- OVERDATA:
- CMP CS:DMAFLAG,0 ;Is DMAFLAG for DAC still in Use?
- JZ OK
- MOV CS:ERROR,1 ;DMA in use error
- JMP EXIT2
- OK:
- MOV AX,0 ;Reset error
- MOV CS:ERROR,AX
- CMP CS:SB_IRQ,-1 ;See if IRQ was available
- JNE TEST_SB
- CALL SBFINDIRQ ;Find IRQ if none given
- CMP CS:ERROR,0 ;Check for errors
- JE TEST_SB
- JMP EXIT2
- TEST_SB:
- CMP CS:SB_TEST,0 ;Has SB been tested?
- JNE OK1
- CALL FIND_DV ;See if in Desqview?
- MOV AX,CS:SB_IRQ ;Get IRQ from environment
- MOV CS:IRQ,AX ;and save it for later
- CALL SBFINDIRQ ;Test IRQ/DMA operation
- CMP CS:ERROR,0 ;Check to see if IRQ was found OK
- JE IRQ_FOUND
- JMP EXIT2
- IRQ_FOUND:
- CMP CS:IRQ,0 ;See if IRQ was available
- JE SBOK
- MOV AX,CS:IRQ ;if it was
- CMP AX,CS:SB_IRQ ;see if it is the same as the IRQ found
- JE SBOK
- MOV CS:ERROR,6 ;indicate wrong IRQ found in environment
- SBOK: MOV CS:SB_TEST,1
- CMP CS:ERROR,0 ;Check to see if IRQ was found ok?
- JE OK1
- JMP EXIT2
- OK1:
- CMP CS:SB_TYPE,-1 ;If SB is type -1
- JE OK2 ;don't check dsp version
- CMP CS:SB_VER,00
- JNZ OK2
- CALL GET_DSP_VER ;Check DSP version for maximum playback
- OK2: LES DI,PARMA ;GET SOUND BUFFER POINTER
- MOV CS:BUFFER,DI ;AND SAVE
- MOV DI,ES
- MOV CS:BUFFER[2],DI
-
- MOV BX,PARMB ;Get number of samples
- CMP BX,0 ;Check for zero samples
- JNE SAVE_S
- MOV CS:ERROR,8
- SAVE_S: MOV CS:SAMPLES,BX ;AND SAVE
-
- MOV AX,PARMF ;Get number of sound channels
- AND AX,02H ;Limit to mono or stereo
- MOV CS:STEREO,AX
-
- MOV BX,PARMC ;Get frequency & calculate time constant
- CMP CS:STEREO,2 ;Half frequency for sb16
- JNE FREQOK
- CMP CS:SB_VER,0400H
- JL FREQOK
- SHR BX,1
- FREQOK: MOV DX,000FH
- MOV AX,04240H
- DIV BX
- XOR AH,AH
- SUB AH,AL
- MOV AL,AH
- XOR AH,AH
- MOV CS:TIME_CONST,AX
- CMP AL,0EAH ;Check playback speed
- JBE L18
- MOV AX,00EAH ;Limit playback speed to 44,100 hz
- MOV CS:TIME_CONST,AX
- L18: CMP CS:SB_VER,0400H ;Skip high speed mode for SB16
- JGE L24
- MOV CS:DSP_SPEED,01
- L24: CMP CS:SB_VER,0200H
- JAE L22
- CMP CS:TIME_CONST,0D4H ;Is playback greater than 22,727 hz?
- JBE L22
- MOV AX,00D4H ;Limit to 22,727 hz if DSP version < 2.00
- MOV CS:TIME_CONST,AX
- L22: CMP CS:TIME_CONST,0D4H ;Is playback less than 22,727 hz?
- JA L19
- MOV CS:DSP_SPEED,00
- L19:
- MOV AX,PARMD ;DSP DMA mode
- CMP CS:SB_VER,0400H ;Limit to 4 modes if not SB16
- JGE L33
- AND AX,03 ;Limit to 4 modes
- L33: AND AX,07 ;Limit to 8 modes for SB16
- MOV BX,AX
- MOV AL,DSP_DMA_MODE[BX]
- MOV CS:DMA_MODE,AL
- MOV AX,PARME ;Mixer sound volume
- MOV DX,0
- MOV BX,13
- DIV BX
- SHL AX,1
- MOV CS:VOLUME,AX
- CALL SET_VOLUME
- CALL INSTALL_ISR ;Install IRQ for Sound Blaster
- CALL SET_MODE ;Set mono or stereo
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0CH
- MOV AL,040H ;Set DSP time constant
- CALL sbdspw
- JNC A1
- MOV CS:ERROR,3 ;DSP Error
- JMP EXIT
- A1: MOV AX,CS:TIME_CONST
- CALL sbdspw
- JNC A2
- MOV CS:ERROR,3 ;DSP Error
- JMP EXIT
- A2:
- INC CS:DMAFLAG ;SET DMAFLAG TO SHOW IN USE
-
- MOV DX,CS:BUFFER[2] ;Convert Buffer Address to 64k Pages & Offset
- MOV AX,CS:BUFFER
- CALL PNT_TO_DMA
- MOV CS:BUFFER,AX ;AND SAVE
- MOV CS:BUFFER[2],DX
- CALL START_DMA
-
- CALL IO_WAIT ;Wait for IRQ from Sound Blaster
-
- EXIT:
- CALL RESTORE_ISR ;Restore IRQ & PIC
- EXIT2: MOV AX,CS:ERROR ;Get error if any
- POP DI ;Restore registers
- POP ES
- POP DS
- POPF
- POP BP ;RESTORE BP
- RET ;RETURN FAR
-
- HANDLER: ;Interrupt for IRQ comes here!
- PUSHF
- PUSH AX
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH DS
- PUSH ES
- sti ;enable interrupts or computer will crash
- CALL sbdsprt
- CMP CS:SB_IRQ,10
- JE ACKIRQ10
- MOV AL,020H
- OUT 020H,AL
- JMP DONE_ACK
- ACKIRQ10:
- MOV AL,020H
- OUT 020H,AL
- OUT 0A0H,AL
- DONE_ACK:
- CMP CS:SAMPLES,0 ;Anymore samples?
- JE L13
- INC CS:BUFFER[2] ;Increment to next page
- MOV CS:BUFFER,0000 ;and set offset to zero
- CALL START_DMA
- JMP EXIT1
- L13: DEC CS:DMAFLAG ;Indicate it is
-
- EXIT1: POP ES
- POP DS
- POP DX
- POP CX
- POP BX
- POP AX
- POPF
- IRET
-
- _sbdma ENDP
-
- sbdspwt PROC NEAR
-
- ;Write to DSP with timeout
-
- PUSH CX
- MOV CX,200H
- MOV AH,AL
- L1: IN AL,DX
- JMP $+2
- OR AL,AL
- JNS L2
- LOOP L1
- STC
- JMP L3
- L2: MOV AL,AH
- OUT DX,AL
- CLC
- L3: POP CX
- RET
-
- sbdspwt ENDP
-
-
- sbdspr PROC NEAR
-
- ;Read DSP
-
- PUSH DX
- MOV DX,CS:SB_IO_ADDR
- ADD DL,0EH
- SUB AL,AL
- L7: IN AL,DX
- JMP $+2
- OR AL,AL
- JNS L7
- SUB DL,04H
- IN AL,DX
- POP DX
- RET
-
- sbdspr ENDP
-
- sbdsprt PROC NEAR
-
- ;Read DSP with timeout
-
- PUSH CX
- PUSH DX
- MOV DX,CS:SB_IO_ADDR
- ADD DL,0EH
- MOV CX,0200H
- L4: IN AL,DX
- JMP $+2
- OR AL,AL
- JS L5
- LOOP L4
- STC
- JMP L6
- L5: SUB DL,04H
- IN AL,DX
- CLC
- L6: POP DX
- POP CX
- RET
-
- sbdsprt ENDP
-
- ;Write to DSP
-
- sbdspw PROC NEAR
-
- PUSH CX
- PUSH BX
- MOV AH,AL
- MOV BX,10
- MOV CX,0ffffH ;After timeout send value anyway
- CLC
- L8: IN AL,DX
- JMP $+2
- JMP $+2
- OR AL,AL
- JNS L8E
- LOOP L8
- DEC BX
- OR BX,BX
- JNZ L8
- STC ;Set Carry to indicate timeout
- L8E: MOV AL,AH
- OUT DX,AL
- POP BX
- POP CX
- RET
-
- sbdspw ENDP
-
- ;Convert FAR pointer to 64k pages and offset
-
- PNT_TO_DMA PROC NEAR
-
- PUSH CX
- MOV CL,4
- ROL DX,CL
- MOV CX,DX
- AND DX,0FH
- AND CX,0FFF0H
- ADD AX,CX
- ADC DX,0
- POP CX
- RET
-
- PNT_TO_DMA ENDP
-
- INSTALL_ISR PROC NEAR
-
- pushf
- push ds
- push es
- CLI
- MOV AX,CS:SB_IRQ
- CMP AX,02
- JE INSTALL
- CMP AX,03
- JE INSTALL
- CMP AX,05
- JE INSTALL
- CMP AX,07
- JE INSTALL
- CMP AX,10
- JE INSTALL
- MOV CS:ERROR,7
- MOV AX,5 ;Use default if error
- INSTALL:
- CALL IRQ_VECT
- MOV AH,035H ;GET INTERRUPT for IRQ 5 AND SAVE IT
- INT 21H
- CLI
- MOV CS:OLD_INTERRUPT,BX
- MOV CS:OLD_INTERRUPT[2],ES
- MOV AX,CS
- MOV DS,AX
- MOV AX,CS:SB_IRQ
- CALL IRQ_VECT
- MOV AH,025H ;AND SET NEW INTERRUPT IRQ 5
- LEA DX,HANDLER
- INT 21H
- pop es
- pop ds
- popf
-
- MOV AX,CS:SB_IRQ ;IRQ 5
- AND AL,08H
- JZ L11
- IN AL,021H ;ENABLE IRQ from PIC
- MOV CS:SAVEPIC,AL
- AND AL,0FBH
- OUT 021H,AL
- MOV DX,00A1H
- JMP L12
- L11: MOV DX,021H
- L12: MOV CX,CS:SB_IRQ ;Sound Blaster IRQ
- AND CL,07H
- MOV AH,01
- SHL AH,CL
- NOT AH
- IN AL,DX
- MOV CS:SAVEPIC2,AL
- AND AL,AH
- OUT DX,AL
- RET
-
- INSTALL_ISR ENDP
-
- RESTORE_ISR PROC NEAR
- ;
- ;Restore IRQ and PICs before exiting
- ;
- PUSH AX
- MOV AX,0
- MOV CS:DMAFLAG,AX ;Indicate DMA done
- LDS DX,CS:OLD_INTERRUPT_ADDR
- MOV AX,CS:SB_IRQ
- CALL IRQ_VECT
- CLI
- MOV AH,025H ;Restore old IRQ 5
- INT 21h
- CLI
- MOV AX,CS:SB_IRQ ;Restore PICs
- AND AL,08
- JZ L31
- MOV AL,CS:SAVEPIC
- OUT 021H,AL
- MOV DX,00A1H
- JMP L32
- L31: MOV DX,0021H
- L32: MOV AL,CS:SAVEPIC2
- OUT DX,AL
- POP AX
- RET
-
- RESTORE_ISR ENDP
-
- IO_WAIT PROC NEAR
- ;
- ; Gives up time slice if time and stops dma if ESC key hit
- ;
- IOWAIT1:
- CMP CS:DMAFLAG,0 ;Is DMAFLAG for DAC still in Use?
- JE DMA_DONE ;Wait until done
- MOV AH,01H ;See if key pressed
- INT 16H
- JZ GET_DMA
- KEY_PRESS:
- MOV AX,0
- INT 16H ;Get the pressed key
- CMP AL,1BH ;See if ESC key hit?
- JNE GET_DMA
- CALL HALT_DMA
- CMP CS:ERROR,0 ;Check for error when halting DMA
- JNE EXIT_IO
- MOV CS:ERROR,0FFFFH ;EXIT ERROR CODE
- JMP EXIT_IO
- ; MOV CS:DMAFLAG,0 ;Reset DMAFLAG to show done
- ; MOV AX,-1 ;and indicate sound halted
- JMP EXIT_IO
- GET_DMA:
- MOV AX,CS:SB_DMA ;Determine DMA count register
- SHL AX,1
- ADD AX,1
- MOV DX,AX
- IN AL,DX ;Get DMA countdown
- MOV AH,AL
- IN AL,DX
- XCHG AL,AH
- CMP AX,5000 ;If greater than 5000 bytes to go
- JG GIVE_CPU ;then give up some cpu time
- WAIT_HERE:
- CMP CS:DMAFLAG,0 ;Is DMAFLAG for DAC still in Use?
- JE DMA_DONE ;Wait until done
- JMP WAIT_HERE
- GIVE_CPU:
- CMP CS:DMAFLAG,0 ;Is DMAFLAG for DAC still in Use?
- JE DMA_DONE ;Wait until done
- CALL GIVE_SLICE ;Give some time up
- JMP IOWAIT1
- DMA_DONE:
- MOV AX,0 ;OK
- EXIT_IO:
- RET
-
-
- IO_WAIT ENDP
-
-
- ; Start DMA transfer
-
- START_DMA PROC NEAR
-
- MOV AX,CS:SB_DMA
- AND AX,03H ;Limit DMA channels to (0-3) 8-BIT
- MOV CS:SB_DMA,AX
- MOV AX,CS:SB_DMA
- ADD AL,04
- OUT 0AH,AL ;Set mask bit channel 1
- JMP $+2
- MOV AL,0FFH
- OUT 0CH,AL ;Clear byte pointer flip/flop
- JMP $+2
- MOV AL,048H ;Write mode
- ADD AX,CS:SB_DMA ;plus DMA channel
- OUT 0BH,AL ;Single mode select read channel 1
- JMP $+2
- MOV BX,CS:SB_DMA ;Get DMA Page Register
- MOV DX,0
- MOV DL,CS:DMA_PAGE[BX]
- MOV AX,CS:BUFFER[2]
- OUT DX,AL ;Set DMA page register
- JMP $+2
- MOV BX,CS:BUFFER
- MOV DX,CS:SB_DMA ;Determine memory address register
- SHL DX,1
- MOV AL,BL
- OUT DX,AL ;Set base and current address
- JMP $+2
- MOV AL,BH
- OUT DX,AL
- JMP $+2
- XOR BX,-1 ;(65536-bx) = #bytes that can be transfered
- MOV AX,CS:SAMPLES ;Get # of samples & subtract 1
- DEC AX ; # SAMPLES - 1
- CMP AX,BX ;# SAMPLES > # that can be DMA?
- JBE L10
- MOV AX,BX ;If yes, use # that can be DMA
- L10:
- CLI
- PUSH AX
- INC DX
- OUT DX,AL ;Base & current word count
- JMP $+2
- MOV AL,AH
- OUT DX,AL
- JMP $+2
- POP AX
- STI
- PUSH AX ;Save number of samples to play
- INC AX ;restore count
- SUB CS:SAMPLES,AX ;Subtract # that can be DMA
- MOV AX,CS:SB_DMA
- OUT 0AH,AL ;Clear channel 1 mask bit to start DMA
-
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0CH
- CMP CS:DSP_SPEED,01 ;Check for high speed mode
- JNZ L21
- MOV AL,048H
- CALL sbdspw
- JNC A11
- MOV CS:ERROR,3 ;DSP not responding
- JMP L20
- A11:
- POP AX ;Get number of samples & send to DSP
- MOV BX,AX
- CALL sbdspw
- JNC A12
- MOV CS:ERROR,3 ;DSP not responding
- JMP L20
- A12:
- MOV AL,BH
- CALL sbdspw
- JNC A13
- MOV CS:ERROR,3 ;DSP not responding
- JMP L20
- A13:
- MOV AL,091H ;High Speed DMA mode
- CALL SBDSPW
- JNC A14
- MOV CS:ERROR,3 ;DSP not responding
- JMP L20
- A14:
- JMP L20
- L21:
- MOV AL,CS:DMA_MODE ;DSP DMA mode for 8-bit DAC
- CALL sbdspw
- JNC A15
- MOV CS:ERROR,3 ;DSP not responding
- JMP L20
- A15:
- CMP CS:DMA_MODE,0C0H ;SB16 stereo?
- JNE A15A
- MOV AX,020H
- CALL sbdspw
- JNC A15A
- MOV CS:ERROR,3 ;DSP not responding
- JMP L20
- A15A: POP AX ;Get number of samples & send to DSP
- MOV BX,AX
- CALL sbdspw
- JNC A16
- MOV CS:ERROR,3 ;DSP not responding
- JMP L20
- A16:
- MOV AL,BH
- CALL sbdspw
- JNC L20
- MOV CS:ERROR,3 ;DSP not responding
- L20: RET
- START_DMA ENDP
-
- ; Calculate interrupt vector for Sound Blaster IRQ (5)
-
- IRQ_VECT PROC NEAR
-
- PUSH BX
- MOV BL,AL
- AND BL,08
- JZ L14
- AND AL,07
- ADD AL,070H
- JMP L15
- L14: ADD AL,08
- L15: CBW
- POP BX
- RET
-
- IRQ_VECT ENDP
-
- SBFINDIRQ PROC NEAR
-
- ; Install ISRs for possible Sound Blaster IRQs
-
- PUSHF
- PUSH DX
- PUSH CX
-
- MOV AX,CS
- MOV DS,AX
- MOV ES,AX
-
- MOV AL,02 ;IRQ 2
- CALL IRQ_VECT ;Get IRQ ISR address
- PUSH AX
- MOV AH,035H ;Get old ISR address and save
- INT 21H
- MOV CS:OLD_ISR2,BX
- MOV CS:OLD_ISR2[2],ES
-
- MOV AX,CS
- MOV DS,AX
- MOV ES,AX
- POP AX
- CLI
- MOV AH,025H ;AND SET NEW INTERRUPT IRQ 2
- LEA DX,HANDLER2
- INT 21H
-
- MOV AL,03 ;IRQ 3
- CALL IRQ_VECT
- PUSH AX
- MOV AH,035H ;Get old ISR address and save
- INT 21H
- MOV CS:OLD_ISR3,BX
- MOV CS:OLD_ISR3[2],ES
-
- MOV AX,CS
- MOV DS,AX
- MOV ES,AX
- POP AX
- CLI
- MOV AH,025H ;AND SET NEW INTERRUPT IRQ 3
- LEA DX,HANDLER3
- INT 21H
-
- MOV AL,05 ;IRQ 5
- CALL IRQ_VECT
- PUSH AX
- MOV AH,035H ;Get old ISR address and save
- INT 21H
- MOV CS:OLD_ISR5,BX
- MOV CS:OLD_ISR5[2],ES
-
- MOV AX,CS
- MOV DS,AX
- MOV ES,AX
- POP AX
- CLI
- MOV AH,025H ;AND SET NEW INTERRUPT IRQ 5
- LEA DX,HANDLER5
- INT 21H
-
- MOV AL,07 ;IRQ 7
- CALL IRQ_VECT
- PUSH AX
- MOV AH,035H ;Get old ISR address and save
- INT 21H
- MOV CS:OLD_ISR7,BX
- MOV CS:OLD_ISR7[2],ES
-
- MOV AX,CS
- MOV DS,AX
- MOV ES,AX
- POP AX
- CLI
- MOV AH,025H ;AND SET NEW INTERRUPT IRQ 7
- LEA DX,HANDLER7
- INT 21H
-
- MOV AL,10 ;IRQ 10
- CALL IRQ_VECT
- PUSH AX
- MOV AH,035H ;Get old ISR address and save
- INT 21H
- MOV CS:OLD_ISR10,BX
- MOV CS:OLD_ISR10[2],ES
-
- MOV AX,CS
- MOV DS,AX
- MOV ES,AX
- POP AX
- CLI
- MOV AH,025H ;AND SET NEW INTERRUPT IRQ 10
- LEA DX,HANDLER10
- INT 21H
- IN AL,021H ;ENABLE IRQS from PIC1
- MOV CS:SAVEPIC,AL
- AND AL,053H
- OUT 021H,AL
- IN AL,0A1H ;ENABLE IRQS from PIC2
- MOV CS:SAVEPIC2,AL
- AND AL,0FBH
- OUT 0A1H,AL
-
- MOV CS:SB_IRQ,0 ;Set IRQ to 0 and see if it changes
-
- CALL TEST_DMA ;Start short DMA and see if it works
- CMP CS:ERROR,0
- JNE FOUNDIRQ
-
- MOV CX,0ffffh
- IRQWAIT:
- CALL GIVE_SLICE ;Give some time up
- MOV AX,CS:SB_IRQ ;Wait for interrupt to occur
- CMP AX,02 ;with Time-Out
- JE FOUNDIRQ
- CMP AX,03
- JE FOUNDIRQ
- CMP AX,05
- JE FOUNDIRQ
- CMP AX,07
- JE FOUNDIRQ
- CMP AX,10
- JE FOUNDIRQ
- LOOP IRQWAIT
-
- IN AL,08H ;Read DMA status register
- JMP $+2
- IN AL,08H ;and again
- CMP AL,0 ;Is status all clear?
- JE IRQERR ;If 0 then IRQ error
- MOV CS:ERROR,5 ;DMA error
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0CH
- MOV AL,080H
- OUT DX,AL ;Send 1 byte to fix DSP
- MOV CX,0ffffh ;Wait for interrupt
- IRQWAIT1:
- CALL GIVE_SLICE ;Give some time up
- MOV AX,CS:SB_IRQ ;Wait for interrupt to occur
- CMP AX,02 ;with Time-Out
- JE FOUNDIRQ
- CMP AX,03
- JE FOUNDIRQ
- CMP AX,05
- JE FOUNDIRQ
- CMP AX,07
- JE FOUNDIRQ
- CMP AX,10
- JE FOUNDIRQ
- LOOP IRQWAIT1
-
- IRQERR: MOV CS:ERROR,2 ;IRQ error (IRQ did not occur)
-
- FOUNDIRQ:
- CLI
- MOV AL,CS:SAVEPIC ;Restore IRQs as found
- OUT 021H,AL
- MOV AL,CS:SAVEPIC2
- OUT 0A1H,AL
-
- MOV AL,02 ;IRQ 2
- CALL IRQ_VECT
- CLI
- MOV AH,025H
- LDS DX,CS:OLD_ISR2_ADDR
- INT 21H ;Restore OLD vector
-
- MOV AL,03 ;IRQ 3
- CALL IRQ_VECT
- CLI
- MOV AH,025H
- LDS DX,CS:OLD_ISR3_ADDR
- INT 21H ;Restore OLD vector
-
- MOV AL,05 ;IRQ 5
- CALL IRQ_VECT
- CLI
- MOV AH,025H
- LDS DX,CS:OLD_ISR5_ADDR
- INT 21H ;Restore OLD vector
-
- MOV AL,07 ;IRQ 7
- CALL IRQ_VECT
- CLI
- MOV AH,025H
- LDS DX,CS:OLD_ISR7_ADDR
- INT 21H ;Restore OLD vector
-
- MOV AL,10 ;IRQ 10
- CALL IRQ_VECT
- CLI
- MOV AH,025H
- LDS DX,CS:OLD_ISR10_ADDR
- INT 21H ;Restore OLD vector
-
- MOV AX,CS:SB_IRQ ;return with SB irq
-
- POP CX
- POP DX
- POPF
- RET
-
- HANDLER2:
- PUSH DX
- PUSH AX
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0EH
- IN AL,DX
- MOV CS:SB_IRQ,02
- MOV AL,020H
- OUT 20H,AL
- POP AX
- POP DX
- IRET
-
- HANDLER3:
- PUSH DX
- PUSH AX
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0EH
- IN AL,DX
- MOV CS:SB_IRQ,03
- MOV AL,020H
- OUT 20H,AL
- POP AX
- POP DX
- IRET
-
- HANDLER5:
- PUSH DX
- PUSH AX
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0EH
- IN AL,DX
- MOV CS:SB_IRQ,05
- MOV AL,020H
- OUT 20H,AL
- POP AX
- POP DX
- IRET
-
- HANDLER7:
- PUSH DX
- PUSH AX
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0EH
- IN AL,DX
- MOV CS:SB_IRQ,07
- MOV AL,020H
- OUT 20H,AL
- POP AX
- POP DX
- IRET
-
- HANDLER10:
- PUSH DX
- PUSH AX
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0EH
- IN AL,DX
- MOV CS:SB_IRQ,10
- MOV AL,020H
- OUT 020H,AL
- OUT 0A0H,AL
- POP AX
- POP DX
- IRET
-
- SBFINDIRQ ENDP
-
- ;Get the Sound Blaster DSP version
-
- GET_DSP_VER PROC NEAR
-
- PUSH CX
- MOV CX,10
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0CH
- MOV AL,0E1H
- CALL sbdspw
- JNC A21
- MOV CS:ERROR,3 ;DSP not responding
- JMP L23
- A21:
- G1: CALL sbdsprt
- CMP AL,0AAH ;Fix error in reading version
- JNZ G2
- LOOP G1
- MOV CS:ERROR,4 ;DSP error not responding or no version
- JMP L23
- G2: MOV AH,AL
- CALL sbdsprt
- MOV CS:SB_VER,AX
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0CH
- MOV AL,0E1H
- CALL sbdspw
- JNC A22
- MOV CS:ERROR,3 ;DSP not responding
- JMP L23
- A22:
- CALL sbdsprt
- MOV AH,AL
- CALL sbdsprt
- CMP CS:SB_VER,AX
- JE L23
- MOV AX,00
- MOV CS:SB_VER,AX
- L23:
- POP CX
- RET
-
- GET_DSP_VER ENDP
-
- ; Test Sound Blaster DMA transfer
-
- TEST_DMA PROC NEAR
-
- MOV DX,CS
- LEA AX,TESTBUFFER
- CALL PNT_TO_DMA
- PUSH AX
- PUSH DX ;SAVE CONVERTED BUFFER ADDRESS
- MOV AL,0FFH
- OUT 00CH,AL ;Clear byte pointer flip/flop
- JMP $+2
- MOV AX,CS:SB_DMA
- ADD AL,04
- OUT 0AH,AL ;Set mask bit to channel
- JMP $+2
- MOV AL,048H
- ADD AX,CS:SB_DMA
- OUT 0BH,AL ;Single mode select read channel
- JMP $+2
- MOV BX,CS:SB_DMA
- MOV DX,0
- MOV DL,CS:DMA_PAGE[BX]
- POP BX ;Restore converted buffer address
- MOV AL,BL
- OUT DX,AL ;Set DMA page register
- JMP $+2
- POP AX
- MOV DX,CS:SB_DMA ;Determine memory address register
- SHL DX,1
- OUT DX,AL ;Set base and current address
- JMP $+2
- MOV AL,AH
- OUT DX,AL
- JMP $+2
- MOV BX,AX
- XOR BX,-1 ;(65536-BX) = # BYTES THAT CAN BE TRANSFERED
- MOV AX,0 ;# samples - 1
- CMP AX,BX
- JBE L100
- MOV AX,BX
- L100:
- CLI
- INC DX
- OUT DX,AL ;Base & current word count
- JMP $+2
- MOV AL,AH
- OUT DX,AL
- JMP $+2
- STI
- MOV AX,CS:SB_DMA
- OUT 0AH,AL ;Clear channel 1 mask bit to start DMA
- JMP $+2
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0CH
- MOV AL,040H
- CALL sbdspw ;Set DSP time constant
- JNC A31
- MOV CS:ERROR,3 ;DSP not responding
- JMP A35
- A31:
- MOV AL,064H
- CALL sbdspw
- JNC A32
- MOV CS:ERROR,3 ;DSP not responding
- JMP A35
- A32:
- MOV AL,014H
- CALL sbdspw ;DMA mode 8-bit DAC
- JNC A33
- MOV CS:ERROR,3 ;DSP not responding
- JMP A35
- A33:
- MOV AX,0000 ;Number of bytes to be sent to DSP is 1
- CALL sbdspw ;#samples to be sent to DSP
- JNC A34
- MOV CS:ERROR,3 ;DSP not responding
- JMP A35
- A34:
- MOV AL,AH
- CALL sbdspw
- JNC A35
- MOV CS:ERROR,3 ;DSP not responding
- A35:
- RET
-
- TEST_DMA ENDP
-
- ; Halt DMA transfer
-
- HALT_DMA PROC NEAR
-
- MOV AX,CS ;Set DS to CS
- MOV DS,AX
- MOV AX,0001
- CMP CS:DMAFLAG,0 ;Is DMAFLAG for DAC still in Use?
- JE H_END ;Wait until done
- CMP CS:DSP_SPEED,01 ;In high speed?
- JNZ H_RESET
- CALL DSP_RESET ;In high speed DSP must be reset first
- H_RESET:
- CALL STOP_DMA
- CALL RESTORE ;Restore IRQ, etc.
- H_END: RET
-
- HALT_DMA ENDP
-
- DSP_RESET PROC NEAR
-
- MOV DX,CS:SB_IO_ADDR
- ADD DL,06
- MOV AL,01
- OUT DX,AL
- IN AL,DX
- IN AL,DX
- IN AL,DX
- IN AL,DX
- SUB AL,AL
- OUT DX,AL
- MOV BL,10H
- D_GET: CALL sbdsprt
- CMP AL,0AAH
- JZ D_END
- DEC BL
- JNZ D_GET
- MOV AX,0002 ;I/O read/write fail
- STC
- JMP D_END1
- D_END: SUB AX,AX
- D_END1: OR AX,AX
- RET
-
- DSP_RESET ENDP
-
- STOP_DMA PROC NEAR
-
- PUSHF
- PUSH SI
- MOV AH,0D0H ;HALT DMA IN PROGRESS
- MOV BX, OFFSET DMAFLAG
- SUB CX,CX
- MOV DX,CS:SB_IO_ADDR
- ADD DL,0CH
- MOV SI,0FFFFH
- S1: STI
- CMP CL,[BX] ;Is dsp in use?
- JZ SE
- CLI
- IN AL,DX
- OR AL,AL
- JS S2
- DEC SI
- JNZ S1
- S5: MOV CS:ERROR,3 ;DSP error (not responding)
- JMP SE
- S2: MOV SI,0FFFFH ;Timeout Period
- S3: DEC SI
- JZ S5
- IN AL,DX
- OR AL,AL
- JS S3
- MOV AL,AH
- OUT DX,AL
- SE: POP SI
- POPF
- RET
-
- STOP_DMA ENDP
-
- RESTORE PROC NEAR
-
- MOV AL,04 ;DMA channel mask register
- ADD AX,CS:SB_DMA
- OUT 0AH,AL
- MOV AX,0
- MOV CS:DMAFLAG,AX ;Indicate it is
- LDS DX,CS:OLD_INTERRUPT_ADDR
- MOV AX,CS:SB_IRQ
- CALL IRQ_VECT
- CLI
- MOV AH,025H ;Restore old IRQ 5
- INT 21h
- CLI
- MOV AX,CS:SB_IRQ ;Restore PICs
- AND AL,08
- JZ R10
- MOV AL,CS:SAVEPIC
- OUT 021H,AL
- MOV DX,00A1H
- JMP R11
- R10: MOV DX,0021H
- R11: MOV AL,CS:SAVEPIC2
- OUT DX,AL
- MOV DX,CS:SB_IO_ADDR ;Acknowledge DSP interrupt
- ADD DL,0EH
- IN AL,DX
- RET
-
- RESTORE ENDP
-
- _sbdelay PROC FAR
- ;
- ; _sbdelay FAR Procedure for C Written by John A. Ball January 9, 1994
- ;
- ; Causes a time delay using the Sound Blaster DSP
- ;
- ; int error sbdelay(char tc, int period);
- ;
- PARMA1 EQU [BP+6] ;Time Constant
- PARMB1 EQU [BP+8] ;Delay period
-
- PUSH BP ;Save stack Frame
- MOV BP,SP
- PUSHF
- PUSH DS ;Save registers
- PUSH ES
- PUSH DI
-
- MOV AX,DGROUP ;Set DS = our data segment
- MOV DS,AX
-
- CMP CS:DMAFLAG,0 ;Is DMAFLAG for DAC still in Use?
- JZ DELAY
- MOV CS:ERROR,1 ;DMA in use error
- JMP EXIT3
- DELAY: CMP CS:SB_IRQ,2 ;See if there is a known valid IRQ
- JE DELAY1
- CMP CS:SB_IRQ,3
- JE DELAY1
- CMP CS:SB_IRQ,5
- JE DELAY1
- CMP CS:SB_IRQ,7
- JE DELAY1
- CMP CS:SB_IRQ,10
- JE DELAY1
- CALL SBFINDIRQ ;Else find the IRQ
- MOV CS:SB_TEST,1
- CMP CS:ERROR,0 ;Check to see if IRQ was found
- JE DELAY1
- JMP EXIT3
- DELAY1:
- CALL INSTALL_ISR ;Install ISR for Sound Blaster IRQ & PIC
-
- MOV CX,PARMA1 ;GET TIME CONSTANT
- MOV BX,PARMB1 ;Get delay period
- MOV DX,CS:SB_IO_ADDR
- ADD DX,0CH
- MOV AL,040H ;Set Time Constant
- CALL sbdspw
- MOV AL,CL
- CALL sbdspw
- MOV AL,080H ;Set Silence Length
- CALL sbdspw
- MOV AL,BL ;and send Period
- CALL sbdspw
- MOV AL,BH
- CALL sbdspw
-
- INC CS:DMAFLAG ;SET DMAFLAG TO SHOW IN USE
-
- CALL IO_WAIT ; and wait for IRQ to occur
-
- CALL RESTORE_ISR ; RESTORE ISR and PIC
- EXIT3: MOV AX,CS:ERROR
- POP DI ;Restore registers
- POP ES
- POP DS
- POPF
- POP BP ;RESTORE BP
- RET
- _sbdelay ENDP
-
- GIVE_SLICE PROC NEAR
- CMP CS:IN_DV,0 ;See if in DESQview?
- JNE DV
- INT 28H ;MS-DOS idle handler
- MOV AX,1680H
- INT 2FH ;MS-DOS idle call
- JMP DV_EXIT
- DV:
- MOV AX,1000H ;Give up time slice to DESQview
- INT 15H
- DV_EXIT:
- RET
- GIVE_SLICE ENDP
-
- FIND_DV PROC NEAR
- PUSH BX
- PUSH CX
- PUSH DX
- MOV CX,'DE'
- MOV DX,'SQ'
- MOV AX,2B01H
- INT 21H
- CMP AL,0FFH
- JE NO_DV
- MOV AX,BX
- MOV CS:IN_DV,1
- JMP E_F
- NO_DV:
- MOV AX,0
- E_F:
- POP DX
- POP CX
- POP BX
- RET
- FIND_DV ENDP
-
- SET_VOLUME PROC NEAR
-
- MOV AX,CS:SB_VER ;Get DSP version and see if card has mixer
- CMP AX,0300H ;Versions 3 and above have mixer chip
- JL EXIT_VOL
- MOV AX,CS:VOLUME ;Get volume and convert to mixer format
- MOV CX,4
- MOV BX,AX
- SHL AX,CL
- ADD BX,AX
- MOV DX,CS:SB_IO_ADDR
- ADD DX,04H
- MOV AX,04H ;Voice Volume Register
- OUT DX,AL
- INC DX
- MOV AX,BX ;Get volume and set
- OUT DX,AL
- EXIT_VOL:
- RET
-
- SET_VOLUME ENDP
-
- SET_MODE PROC NEAR
-
- MOV AX,CS:STEREO ;Get mono or stereo mode
- CMP AX,CS:PRE_MODE ;Same mode as before?
- JE SM_EXIT
- CMP CS:SB_VER,0300H ;Sound Blaster Pro
- JL SM_EXIT
- CMP CS:SB_VER,0400H ;only
- JGE SM_EXIT
- MOV DX,CS:SB_IO_ADDR
- ADD DX,4
- MOV CS:PRE_MODE,AX ;Save current mode
- CMP AX,2 ;Stereo or mono
- JE SET_STEREO
- MOV AL,00CH ;Restore filter status
- OUT DX,AL
- INC DX
- MOV AX,CS:OUT_FILTER
- OUT DX,AL
- DEC DX
- MOV AL,00EH ;Set hardware to mono mode
- OUT DX,AL
- INC DX
- IN AL,DX
- AND AL,0FDH
- OUT DX,AL
- JMP SM_EXIT
- SET_STEREO:
- MOV AX,00EH ;Set hardware to stereo mode
- OUT DX,AL
- INC DX
- IN AL,DX
- OR AL,002H
- OUT DX,AL
- DEC DX
- MOV AX,00EH
- OUT DX,AL
- INC DX
- IN AL,DX
- MOV CS:OUT_FILTER,AX
- OR AL,020H
- OUT DX,AL
- SM_EXIT:
- RET
-
- SET_MODE ENDP
-
- _TEXT ENDS
- END
-
-